import { fromTemplate } from '$lib/builder';
import { makeLandscape } from '$lib/landscape';
import { placeOnMap } from '$lib/pos3';
import { distribute, random } from '$lib/random';
import { hasComponent } from '$lib/ecs';
import { Coal, Foliage, Gold, Water, groundTemplate, oceanTemplate, sandTemplate, shallowWaterTemplate, surfaceGroundTemplate } from './ground';
import { appleTreeTemplate, bushTemplate, grassTemplate, treeTemplate } from './foliage';
import { mapHeight, mapWidth } from './size';
import * as p5 from 'p5';
import { crowTemlate } from './crow';
import { wormTemplate } from './worm';
import { rabbitTemplate } from './rabbit';

/**
 * Generate random ground map on level z
 * Normally this would be used once
 */
export const randomGround = (world, z) => {
  // Generate basic landscape
  const grid = new Map();
  withNoise((noise) => {
    for (let y = 0; y < mapHeight; ++y) {
      const line = new Map();
      grid.set(y, line);
      for (let x = 0; x < mapWidth; ++x) {
        const dist = 2*Math.min(
          x / mapWidth,
          y / mapHeight,
          (mapWidth-x) / mapWidth,
          (mapHeight-y) / mapHeight
        );
        const groundOrWater = dist + noise(x*0.1, y*0.1) - 0.7;
        const tmplt = distribute(groundOrWater, [
          [oceanTemplate, 0.15],
          [shallowWaterTemplate, 0.05],
          [sandTemplate, 0.05],
          [surfaceGroundTemplate, 0.75],
        ]);
        const e = fromTemplate(world, tmplt);
        makeLandscape(world, e);
        placeOnMap(world, e, x, y, z);
        line.set(x, e);
      }
    }
  });
  // Foliage
  withNoise((noise) => {
    for (let y = 0; y < mapHeight; ++y) {
      for (let x = 0; x < mapWidth; ++x) {
        const greens = noise(x*0.6, y*0.6);
        const e = grid.get(y).get(x);
        if (!hasComponent(world, Foliage, e))
          continue;
        Foliage.amount[e] = greens * 50;
        const foliage = distribute(greens, [
          [undefined, 0.2],
          [grassTemplate, 0.3],
          [bushTemplate, 0.2],
          ['tree', 0.3],
        ]);
        if (foliage) {
          let tmplt;
          if (foliage === 'tree') {
            tmplt = distribute(random(), [
              [treeTemplate, 0.5],
              [appleTreeTemplate, 0.5],
            ]);
          } else {
            tmplt = foliage;
          }
          const e = fromTemplate(world, tmplt);
          placeOnMap(world, e, x, y, z);
        }
      }
    }
  });
  // Crows
  withNoise((noise) => {
    for (let y = 0; y < mapHeight; ++y) {
      for (let x = 0; x < mapWidth; ++x) {
        const crow = noise(x, y);
        if (crow > 0.8) {
          const e = fromTemplate(world, crowTemlate);
          placeOnMap(world, e, x, y, z);
        }
      }
    }
  });
  // Rabbits. TODO: spawn from ships
  withNoise((noise) => {
    for (let y = 0; y < mapHeight; ++y) {
      for (let x = 0; x < mapWidth; ++x) {
        const rabbit = noise(x, y);
        if (rabbit > 0.8) {
          const e = fromTemplate(world, rabbitTemplate);
          placeOnMap(world, e, x, y, z);
        }
      }
    }
  });
};

export const withNoise = (f) => {
  const seed = Math.floor(random.int32());
  let noise;
  new p5((p) => {
    p.noiseSeed(seed);
    noise = p.noise;
    // UGH this doesn't work for some reason
    p.noCanvas();
  });
  f(noise);
};

/**
 * Generate random underground map filled with ground with random resoures
 */
export const randomUnderground = (world, z) => {
  const grid = new Map();
  for (let y = 0; y < mapHeight; ++y) {
    const line = new Map();
    grid.set(y, line);
    for (let x = 0; x < mapWidth; ++x) {
      const e = fromTemplate(world, groundTemplate);
      makeLandscape(world, e);
      placeOnMap(world, e, x, y, z);
      line.set(x, e);
    }
  }
  withNoise((noise) => {
    for (let y = 0; y < mapHeight; ++y) {
      for (let x = 0; x < mapWidth; ++x) {
        const e = grid.get(y).get(x);
        Coal.amount[e] = noise(x*0.2, y*0.2)*100;
      }
    }
  });
  withNoise((noise) => {
    for (let y = 0; y < mapHeight; ++y) {
      for (let x = 0; x < mapWidth; ++x) {
        const e = grid.get(y).get(x);
        Gold.amount[e] = noise(x*0.2, y*0.2)*100;
      }
    }
  });
  withNoise((noise) => {
    for (let y = 0; y < mapHeight; ++y) {
      for (let x = 0; x < mapWidth; ++x) {
        const worm = noise(x, y);
        if (worm > 0.8) {
          const e = fromTemplate(world, wormTemplate);
          placeOnMap(world, e, x, y, z);
        }
      }
    }
  });
};
